﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using ElfTyping.Cards;
using System.IO;

namespace ElfTyping.General
{
    /// <summary>
    /// The definitive hub of all things permanent.
    /// Can be saved and loaded.
    /// </summary>
    [Serializable]
    public class PlayerStatus
    {        
        [XmlIgnore()]
        public int MaximumHealth { get; set; }
        [XmlIgnore()]
        public int Strength { get; set; }

        private int _level;
        [XmlIgnore()]
        public int Level
        {
            get { return _level; }
            set
            {
                _level = value;
                Strength = 3 + value;
                MaximumHealth = 8 + 2 * value;
            }
        }

        private int _totalExperience;
        public int TotalExperience
        {
            get { return _totalExperience; }
            set
            {
                Level = GetLevelForExperience(value);
                _totalExperience = value;
            }
        }

        public int Gold { get; set; }
        public Equipment CurrentEquipment { get; set; }
        //public List<string> AllCardsOwned
        //{
        //    get {
        //        return CardManager.GetManager().SerializeToList();
        //    }
        //    set {
        //        CardManager.GetManager().DeserializeFromList(value);
        //    }
        //}
        //public List<string> AllPiecesOwned
        //{
        //    get { return PuzzlePieceManager.GetManager().SerializeToList(); }
        //    set { PuzzlePieceManager.GetManager().DeserializeFromList(value); }
        //}
        public List<string> AllCardsOwned { get; set; }
        public List<string> AllPiecesOwned { get; set; }
        public int FurthestQuest { get; set; }
        public int FurthestChapter { get; set; }
        public int CurrentQuest { get; set; }
        public int CurrentChapter { get; set; }

        private DateTime _lastSaveTime;
        public DateTime XmlLastSaveTime
        {
            get { return DateTime.Now; }
            set { _lastSaveTime = value; }
        }

        [XmlIgnore()]
        public DateTime LastSaveTime
        {
            get { return _lastSaveTime; }
            set { _lastSaveTime = value; }
        }

        private static PlayerStatus _singleton = null;
        public static PlayerStatus GetStatus()
        {
            if (_singleton == null)
            {
                _singleton = new PlayerStatus();
            }
            return _singleton;
        }
        private PlayerStatus()
        {
            CurrentEquipment = new Equipment();
            GainExperience(0);
        }

        /// <summary>
        /// Give the player experience and do leveling up.
        /// </summary>
        /// <returns>Whether the player leveled up.</returns>
        public bool GainExperience(int experience)
        {
            int levelBeforeExp = Level;
            TotalExperience = TotalExperience + experience;

            return (levelBeforeExp != Level);
        }

        public static int GetExperienceUpToLevel(int level)
        {
            // 10x^2 + 10x - 20
            // Z+ => {0, 40, 100, 180, 280, 400, ...}
            return 10 * (level * level + level - 2);
        }

        public static int GetLevelForExperience(int experience)
        {
            // quadratic formula. int to round down.
            return (int)((-10.0 + Math.Sqrt(100.0 + 4.0 * 10 * (20 + experience))) / 20.0 + 0.00001);
        }

        private XmlSerializer MakeSerializer()
        {
            return new XmlSerializer(
                typeof(PlayerStatus),
                new Type[] {
                    typeof(Equipment),
                    typeof(List<string>),
                    typeof(string),
                    typeof(int),
                    typeof(DateTime)
                });
        }

        const string SavePath = @"test_save.xml";
        public void SaveToXml()
        {
            // update dynamic stuff with the latest
            AllCardsOwned = CardManager.GetManager().SerializeToList();
            AllPiecesOwned = PuzzlePieceManager.GetManager().SerializeToList();

            Stream outputStream = File.Create(SavePath);
            XmlSerializer formatter = MakeSerializer();
            formatter.Serialize(outputStream, this);
            outputStream.Close();
        }

        public void LoadFromXml()
        {
            if (File.Exists(SavePath))
            {
                Stream inputStream = File.OpenRead(SavePath);
                XmlSerializer formatter = MakeSerializer();
                PlayerStatus status = (PlayerStatus)formatter.Deserialize(inputStream);
                inputStream.Close();

                // TODO: see if this will work?
                //_singleton = status;

                TotalExperience = 0;
                GainExperience(status.TotalExperience);
                Gold = status.Gold;
                CurrentEquipment = status.CurrentEquipment;
                AllCardsOwned = status.AllCardsOwned;
                AllPiecesOwned = status.AllPiecesOwned;
                FurthestQuest = status.FurthestQuest;
                FurthestChapter = status.FurthestChapter;
                CurrentQuest = status.CurrentQuest;
                CurrentChapter = status.CurrentChapter;
                LastSaveTime = status.LastSaveTime;

                CardManager.GetManager().DeserializeFromList(AllCardsOwned);
                PuzzlePieceManager.GetManager().DeserializeFromList(AllPiecesOwned);
            }
        }
    }

    [Serializable]
    public class Equipment
    {
        [XmlIgnore()]
        private static CardManager Manager = CardManager.GetManager();

        public string Arrow_ID
        {
            get { return (Arrow != null) ? Arrow.ID : ""; }
            set { Arrow = (ArrowCard)Manager.GetCardWithID(value); }
        }
        public string Spell1_ID
        {
            get { return (Spell1 != null) ? Spell1.ID : ""; }
            set { Spell1 = (SpellCard)Manager.GetCardWithID(value); }
        }
        public string Spell2_ID
        {
            get { return (Spell2 != null) ? Spell2.ID : ""; }
            set { Spell2 = (SpellCard)Manager.GetCardWithID(value); }
        }
        public string Passive1_ID
        {
            get { return (Passive1 != null) ? Passive1.ID : ""; }
            set { Passive1 = (PassiveCard)Manager.GetCardWithID(value); }
        }
        public string Passive2_ID
        {
            get { return (Passive2 != null) ? Passive2.ID : ""; }
            set { Passive2 = (PassiveCard)Manager.GetCardWithID(value); }
        }

        [XmlIgnore()]
        public ArrowCard Arrow { get; set; }
        [XmlIgnore()]
        public SpellCard Spell1 { get; set; }
        [XmlIgnore()]
        public SpellCard Spell2 { get; set; }
        [XmlIgnore()]
        public PassiveCard Passive1 { get; set; }
        [XmlIgnore()]
        public PassiveCard Passive2 { get; set; }
    }
}
